#pragma once
#include<iostream>
#include<string>
#include <sstream>
#include<vector>
#include<fstream>
#include <unordered_map>
const std::string base_sep ="\r\n";
const std::string arg_sep="?";
const std::string prefixpath ="Myhtml";
const std::string suffix_sep=".";
const std::string homepage="index.html";
const std::string html_404 ="404.html";
const std::string head_sep =":";
const std::string httpversion="HTTP/1.0";
class HttpRequest
{
public:
	HttpRequest():_blank_line(base_sep),_path(prefixpath){};
	std::string GetLine(std::string& httprequest)//从string中取一行
	{
		ssize_t pos = httprequest.find(base_sep);
		if(pos==std::string::npos) return std::string();//读取不到设定的分隔符就返回空串
		std::string line = httprequest.substr(0,pos);
		httprequest.erase(0,pos+base_sep.size());
		return line.empty()?base_sep:line;

	};
	void ParseReqLine()
	{
		std::stringstream ss(_req_line);
		ss>>_method>>_url>>_version;
		if(strcasecmp(_method.c_str(),"GET")==0)
		{
			ssize_t pos =_url.find(arg_sep);
			if(pos!=std::string::npos)
			{
			_body_text=_url.substr(pos+arg_sep.size());
			_url.resize(pos);
			};
		};//提取get方法传过来的参数
		_path+=_url;
		if(_path[_path.size()-1]=='/')//如果访问根目录，默认是首页
		_path+=homepage;
		ssize_t pos =_path.rfind(suffix_sep);//获取路径后缀
		if(pos!=std::string::npos)
		_suffix= _path.substr(pos);
		else
		_suffix =".default"; 
	};
	void ParseReqHander()
	{
		for(auto str:_req_headers)
		{
			ssize_t pos = str.find(head_sep);
			if(pos!=std::string::npos)
			{
				std::string K,V;
				K=str.substr(0,pos);
				V=str.substr(pos+head_sep.size());
				if(K.empty()||V.empty())
					continue;
				_headers_kv.emplace(K,V);
			}
		};

	};
	void Deserialize(std::string& httprequest)
	{
		//基本反序列化
		_req_line = GetLine(httprequest);
		while(1)
		{
			std::string hander = GetLine(httprequest);
			if(hander.empty()||hander==base_sep)//读取到的报头不完整或者是读到空白行终止
				break;
			_req_headers.emplace_back(hander);
		};
		if(!httprequest.empty()) _body_text=httprequest;
		ParseReqLine();
		ParseReqHander();
	};
	void Print()
	{
		cout<<"method:"<<_method<<endl;
		cout<<"url:"<<_url<<endl;
		cout<<"version:"<<_version<<endl;
		cout<<"path:"<<_path<<endl;
		cout<<"_suffix:"<<_suffix<<endl;
		for(auto e:_headers_kv)
		{
			cout<<e.first<<":"<<e.second<<endl;
		};
	};
	const std::string Path()
	{return _path;};
	const std::string Body()
	{return _body_text;};
	const std::string Suffix()
	{return _suffix;};

private:
	//基本的http反序列化的格式
	std::string _req_line;
	std::vector<std::string> _req_headers;
	std::string _blank_line;
	std::string _body_text;
	//进一步反序列化的格式
	std::string _method;
	std::string _url;
	std::string _version;
	std::string _path;//资源路径
	std::string _suffix;//路径后缀
	std::unordered_map<string,string> _headers_kv;
	
};
class HttpResponse
{
public:
	HttpResponse():_blank_line(base_sep),_version(httpversion)
	{};
	void AddCode(int code,const std::string &desc)
	{
		_status_code =code;
		_desc =desc;
	};
	void AddHeader(const std::string& k,const std::string& v)
	{
		_headers_kv.emplace(k,v);
	};
	void AddBodyText(const std::string& body)
	{
		_resp_body_text = body;
	};
	std::string Serialize()
	{
		//构建基本属性
		_status_line = _version+" "+std::to_string(_status_code)+" "+_desc+base_sep;
		for(auto[x,y]:_headers_kv)
		{
			_resp_headers.emplace_back(x+head_sep+y+base_sep);
		};
		//构建序列化应答
		std::string httpresp = _status_line;
		for(auto e:_resp_headers)
			httpresp+=e;
		return httpresp+_blank_line+_resp_body_text;
	};
private:
	//基本属性
	std::string _status_line;
	std::vector<std::string> _resp_headers;
	std::string _blank_line;
	std::string _resp_body_text;
	//进一步的属性
	std::string _version;
	int _status_code;
	std::string _desc;
	std::unordered_map<string,string> _headers_kv;
	
};



struct HttpServer
{
private:
	std::string GetFileContent(const std::string& path)
	{
		std::ifstream in(path,std::ios::binary);
		if(!in.is_open()){
			perror("open");
			return string();
		}
		std::cout << "GetFileContent: path open success " << path << std::endl;
		in.seekg(0,in.end);
		int filesize = in.tellg();
		in.seekg(0,in.beg);
		std::cout << "filesize : " << filesize << std::endl;
		//char content[filesize+1];
		//in.read(content,filesize);//这种不行是因为用char*读取后隐式类型转化为string的时候会在有\0的时候直接终止转化，从而转化的数据不完全
		std::string content(filesize, '\0');
		in.read(&content[0], filesize);
		in.close();
		return content;

	};
public:

	HttpServer()
	{
	_mime_type.insert(std::make_pair(".html", "text/html"));
        _mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair(".png", "image/png"));
        _mime_type.insert(std::make_pair(".default", "text/html"));
        _code_desc.insert(std::make_pair(100, "Continue"));
        _code_desc.insert(std::make_pair(200, "OK"));
        _code_desc.insert(std::make_pair(201, "Created"));
        _code_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_desc.insert(std::make_pair(302, "Found"));
        _code_desc.insert(std::make_pair(404, "Not Found"));
	};
	std::string  HandlerHttpRequest(std::string& httprequest)
	{
		HttpRequest httpreq;
		HttpResponse httpresp;
		httpreq.Deserialize(httprequest);
		if(httpreq.Path()=="Myhtml/redir")
		{
			std::string redir_path = "https://www.qq.com";
           	 httpresp.AddCode(301, _code_desc[301]);
           	 httpresp.AddHeader("Location", redir_path);
		}
		else if(!httpreq.Body().empty())//这种情况是使用GET在URL传参或者使用POST在正文传参
		{//C++语言不适合处理这种业务，一般是重定向到其他程序用其他编程语言来实现
		 cout<<"get info:"<<endl;
		 cout<<httpreq.Body()<<endl;
		}
		else
		{
			std::cout << httpreq.Path() << std::endl;
		std::string content = GetFileContent(httpreq.Path());
		//std::cout << "HandlerHttpRequest: content: " << content << std::endl;
		std::cout << "HandlerHttpRequest: content size:" << content.size() << std::endl;
		if(content.empty())
		{
		content = GetFileContent("Myhtml/404.html");
                httpresp.AddCode(404, _code_desc[404]);
                httpresp.AddHeader("Content-Length", std::to_string(content.size()));
                httpresp.AddHeader("Content-Type", _mime_type[".html"]);
                httpresp.AddBodyText(content);

		}
		else
		{
		httpresp.AddCode(200,_code_desc[200]);
		httpresp.AddHeader("Content-Length",std::to_string(content.size()));
		httpresp.AddHeader("Content-Type",_mime_type[httpreq.Suffix()]);
		httpresp.AddBodyText(content);
		}
		}
		//cout<<httpresp.Serialize()<<endl;
		return httpresp.Serialize();

	};
private:
std::unordered_map<std::string,std::string> _mime_type;
std::unordered_map<int,std::string> _code_desc;

};
